﻿using Inovout.Lambda;
using Inovout.Web.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace System.Web.Mvc.Html
{
    /// <summary>
    /// Widget-Editor
    /// </summary>
    public static class ModelExtensions
    {
        /// <summary>
        /// 针对模型的属性编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型中的属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="modelAccessor">属性访问器表达式</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelPropertyEditor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> modelAccessor, params Expression<Func<TProperty, object>>[] properties)
        {
            return ModelPropertyEditor(html, modelAccessor, properties == null ? null : properties.Select(p => ExpressionHelper.GetExpressionText(p)).ToArray());
        }
        /// <summary>
        /// 针对模型的属性编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型中的属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="modelAccessor">属性访问器表达式</param>
        /// <param name="partialViewName">局部视图名</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelPropertyEditor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> modelAccessor, string partialViewName, params Expression<Func<TProperty, object>>[] properties)
        {
            return ModelPropertyEditor(html, modelAccessor, partialViewName, properties == null ? null : properties.Select(p => ExpressionHelper.GetExpressionText(p)).ToArray());
        }

        /// <summary>
        /// 针对模型的属性编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型中的属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="modelAccessor">属性访问器表达式</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelPropertyEditor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> modelAccessor, string[] properties)
        {
            return ModelPropertyEditor(html, modelAccessor, properties, null);
        }
        /// <summary>
        /// 针对模型的属性编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型中的属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="modelAccessor">属性访问器表达式</param>
        /// <param name="partialViewName">局部视图名</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelPropertyEditor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> modelAccessor, string partialViewName,params string[] properties)
        {
            return ModelPropertyEditor(html, modelAccessor, properties, null, partialViewName);
        }


        internal static IHtmlString ModelPropertyEditor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> modelAccessor, string[] properties, IDictionary<string, object> additionalViewData = null, string partialViewName = "_ModelEditor")
        {
            TProperty model = CachedExpressionCompiler.Process<TModel, TProperty>(modelAccessor)(html.ViewData.Model);
            var viewData = CreateWidgetDataDictionary<TProperty>(model, html.ViewData, properties, additionalViewData);
            viewData.TemplateInfo.HtmlFieldPrefix = ExpressionHelper.GetExpressionText(modelAccessor);
            return html.Partial(partialViewName, viewData);
        }

        /// <summary>
        /// 针对模型的编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="partialViewName">局部视图名</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelEditor<TModel>(this HtmlHelper<TModel> html, string partialViewName, params Expression<Func<TModel, object>>[] properties)
        {
            return ModelEditor(html, partialViewName, properties == null ? null : properties.Select(p => ExpressionHelper.GetExpressionText(p)).ToArray());
        }
        /// <summary>
        /// 针对模型的编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="partialViewName">局部视图名</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelEditor<TModel>(this HtmlHelper<TModel> html, string partialViewName, params string[] properties)
        {
            return ModelEditor(html, html.ViewData.Model, properties, null, partialViewName);
        }

        /// <summary>
        /// 针对模型的编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelEditor<TModel>(this HtmlHelper<TModel> html, params Expression<Func<TModel, object>>[] properties)
        {
            return ModelEditor(html, html.ViewData.Model, properties == null ? null : properties.Select(p => ExpressionHelper.GetExpressionText(p)).ToArray());
        }
        /// <summary>
        /// 针对模型的编辑
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="properties">模型属性对象的属性名数组</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelEditor<TModel>(this HtmlHelper<TModel> html, params string[] properties)
        {
            return ModelEditor(html, html.ViewData.Model, properties);
        }

        internal static IHtmlString ModelEditor<TModel>(this HtmlHelper html, TModel model, string[] properties, IDictionary<string, object> additionalViewData = null, string partialViewName = "_ModelEditor")
        {
            return html.Partial(partialViewName, CreateWidgetDataDictionary<TModel>(model, html.ViewData, properties, additionalViewData));
        }
        /// <summary>
        /// 针对模型的编辑
        /// </summary>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="model">模型对象实例</param>
        /// <param name="metadata">模型元数据</param>
        /// <param name="partialViewName">局部视图名</param>
        /// <returns>IHtmlString对象实例</returns>
        public static IHtmlString ModelEditor(this HtmlHelper html, object model, WidgetModelMetadata metadata = null, string partialViewName = "_ModelEditor")
        {
            var widgetViewData = new WidgetDataDictionary(model, html.ViewData, metadata);
            widgetViewData.TemplateInfo.HtmlFieldPrefix = html.ViewData.TemplateInfo.HtmlFieldPrefix;
            return html.Partial(partialViewName, widgetViewData);
        }
        internal static IHtmlString ModelEditor<TModel>(this HtmlHelper html, TModel model, string partialViewName, IDictionary<string, object> additionalViewData = null)
        {
            return ModelEditor(html, model, null, additionalViewData, partialViewName);
        }
        private static WidgetDataDictionary<TModel> CreateWidgetDataDictionary<TModel>(TModel model, ViewDataDictionary viewData, string[] properties, IDictionary<string, object> additionalViewData = null)
        {
            var widgetViewData = new WidgetDataDictionary<TModel>(model, viewData);

            if (properties != null && properties.Any())
            {
                widgetViewData.WidgetModelMetadata.SelectModelDeclaringTypeProperties(properties);
            }
            widgetViewData.CopyAdditionalViewData(additionalViewData);
            return widgetViewData;
        }
    }
    /// <summary>
    /// 属性辅助类
    /// </summary>
    public static class PropertyHelper
    {
        /// <summary>
        /// 获取属性名
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="propertyAccessor">属性访问器</param>
        /// <returns>属性名</returns>
        public static string Property<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertyAccessor)
        {
            return ExpressionHelper.GetExpressionText(propertyAccessor);
        }
        /// <summary>
        /// 获取属性名
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="propertyAccessor">属性访问器</param>
        /// <returns>属性名</returns>
        public static string Property<TModel, TProperty>(this HtmlHelper html, Expression<Func<TModel, TProperty>> propertyAccessor)
        {
            return ExpressionHelper.GetExpressionText(propertyAccessor);
        }
        /// <summary>
        /// 获取属性名
        /// </summary>
        /// <typeparam name="TModel">模型类型</typeparam>
        /// <typeparam name="TProperty">模型属性类型</typeparam>
        /// <param name="html">HtmlHelper对象实例</param>
        /// <param name="propertyAccessor">属性访问器</param>
        /// <returns>属性名</returns>
        public static string Property<TModel, TProperty>(this HtmlHelper<IEnumerable<TModel>> html, Expression<Func<TModel, TProperty>> propertyAccessor)
        {
            return ExpressionHelper.GetExpressionText(propertyAccessor);
        }
    }
}
